﻿Option Strict On

Public Class Display

    Public m_Form2 As New Form2
    Private Const VertexSize As Integer = 10
    Private m_Matrix As Matrix
    Private ReadOnly m_Host As PictureBox
    Private ReadOnly m_DiffLabel As Label
    Private ReadOnly m_BackBuffer As Bitmap
    Private ReadOnly m_Vertices As New List(Of Point)()
    Private ReadOnly m_Edges As New List(Of Pair(Of Point, Point))()

    Public Sub New(ByVal host As PictureBox, ByVal diff_label As Label)
        m_Host = host
        m_DiffLabel = diff_label
        m_BackBuffer = New Bitmap(m_Host.Width, m_Host.Height)
    End Sub

    Public Sub InitMatrix(ByVal r As Double, ByVal precision As Double)
        m_Matrix = New Matrix(m_Vertices, m_Edges, r, precision, Me)
        m_Matrix.Run()
    End Sub

    Public Sub NextStep()
        m_Matrix.Run()
    End Sub

    Public Sub AddVertex(ByVal where As Point)
        ' For debugging only?
        For Each v In m_Vertices
            AddEdge(where, v)
        Next

        m_Vertices.Add(where)

        OnChanged()
    End Sub

    Public Sub RemoveVertex(ByVal where As Point)
        m_Vertices.Remove(where)
        m_Edges.RemoveAll(Function(e) e.First = where OrElse e.Second = where)
        OnChanged()
    End Sub

    Public Function FindVertex(ByVal where As Point) As Point?
        Dim result = From v In m_Vertices _
                     Let d = Distance(v, where) _
                     Where d <= VertexSize / 2 _
                     Order By d _
                     Select v
        Return If(result.Count() > 0, New Point?(result.First()), Nothing)
    End Function

    Public Sub AddEdge(ByVal from As Point, ByVal [to] As Point)
        m_Edges.Add(New Pair(Of Point, Point)(from, [to]))
        OnChanged()
    End Sub

    Public Sub RemoveEdge(ByVal from As Point, ByVal [to] As Point)
        m_Edges.RemoveAll(Function(edge) edge.First = from AndAlso edge.Second = [to])
        OnChanged()
    End Sub

    Public Sub ReDraw(ByVal Matrix As Double(,), ByVal IndexOf As Dictionary(Of Point, Integer), ByVal difference As Boolean)
        Dim vr = VertexSize \ 2
        Using g = Graphics.FromImage(m_BackBuffer)
            g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
            g.Clear(Color.White)
            For Each v In m_Vertices
                g.DrawEllipse(Pens.Black, v.X - vr, v.Y - vr, VertexSize, VertexSize)
            Next

            For Each e In m_Edges
                Dim c = Color.FromArgb(CInt(255 * Matrix(IndexOf(e.First), IndexOf(e.Second))), Color.Blue)
                Using p As New Pen(c, 2)
                    g.DrawLine(p, e.First, e.Second)
                End Using
            Next
            For Each e In m_Edges
                Dim c = Color.FromArgb(CInt(255 * Matrix(IndexOf(e.Second), IndexOf(e.First))), Color.Blue)
                Using p As New Pen(c, 2)
                    g.DrawLine(p, e.First, e.Second)
                End Using
            Next
        End Using

        m_DiffLabel.Text = If(difference, "different", "nondiff")
        m_DiffLabel.Refresh()

        'm_Host.Invalidate()
        m_Host.Refresh()
        'Host_Paint(m_Host, e)
    End Sub

    Public Sub Draw(ByVal e As PaintEventArgs)
        Host_Paint(m_Host, e)
    End Sub

    Private Sub OnChanged()
        Dim vr = VertexSize \ 2
        Using g = Graphics.FromImage(m_BackBuffer)
            g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
            g.Clear(Color.White)
            For Each v In m_Vertices
                g.DrawEllipse(Pens.Black, v.X - vr, v.Y - vr, VertexSize, VertexSize)
            Next

            For Each e In m_Edges
                g.DrawLine(Pens.Black, e.First, e.Second)
            Next
        End Using

        m_Host.Invalidate()
    End Sub

    Private Sub Host_Paint(ByVal sender As Object, ByVal e As PaintEventArgs)
        e.Graphics.DrawImageUnscaled(m_BackBuffer, 0, 0)
    End Sub

End Class
